#include "tsa_fsm.h"
#include "xprintf.h"

void fsm_init(FSM_DATA * this, const FSM_DESCRIPTOR * pDescriptor, int user)
{
    xprintf("\r\nfsm_init(,,%d)", user);
    this->pDescriptor = pDescriptor;
    this->user = user;
    this->state = pDescriptor->defaultState;
}

void fsm_run(FSM_DATA * this)
{
    int state = this->state;
//    xprintf("\r\nfsm_run(%d) @ %d", this->user, state);
    if(state < this->pDescriptor->totalNumberOfStates)
    {
        const FSM_OPERATION * operation = &(this->pDescriptor->operationsOfState[state]);
        if(operation->run) operation->run(this);
    }
}

void fsm_transit(FSM_DATA * this, int event)
{
    int state = this->state;
    if(event>0) xprintf("\r\nfsm_transit(%d,%d) @ %d", this->user, event, state);
    if(state < this->pDescriptor->totalNumberOfStates && event < this->pDescriptor->totalNumberOfEvents)
    {
        const FSM_TRANSITION_ON_EVENT * transition = &(this->pDescriptor->transitionFromState[state].onEvent[event]);
        /// keep current state
        if(transition->nextState == FSM_KEEP)
        {
            this->fromState = state;
            this->toState = state;
        }
        /// if state changed
        else if(state!=transition->nextState)
        {
            const FSM_OPERATION * operation;
            /// for debugging
            this->event = event;
            this->fromState = state;
            this->toState = transition->nextState;
            /// get current state operations
            operation = &(this->pDescriptor->operationsOfState[state]);
            /// exit current state
            if(operation->exit) operation->exit(this);
            /// perform transition
            if(transition->transit) transition->transit(this);
            /// set new state
            this->state = transition->nextState;
            state = this->state;
            /// get new state operations
            operation = &(this->pDescriptor->operationsOfState[state]);
            /// enter new state
            if(operation->enter) operation->enter(this);
        }
    }
}

